package com.jintian.smart.demo.service;

import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.jintian.smart.base.api.system.constant.AdminCacheConst;
import com.jintian.smart.kernel.common.util.SmartBeanUtil;
import com.jintian.smart.kernel.core.constant.StringConst;
import com.jintian.smart.kernel.core.domain.ResponseDTO;
import com.jintian.smart.kernel.orm.impl.AbstractEntityServiceImpl;
import com.jintian.smart.base.api.demo.dto.CategorySimpleDTO;
import com.jintian.smart.base.api.demo.entity.CategoryBaseEntity;
import com.jintian.smart.base.api.demo.form.CategoryAddForm;
import com.jintian.smart.base.api.demo.form.CategoryTreeQueryForm;
import com.jintian.smart.base.api.demo.form.CategoryUpdateForm;
import com.jintian.smart.base.api.demo.view.CategoryTreeVO;
import com.jintian.smart.base.api.demo.view.CategoryVO;
import com.jintian.smart.demo.mapper.CategoryMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 类目
 */
@Slf4j
@Service
public class CategoryService extends AbstractEntityServiceImpl<CategoryMapper, CategoryBaseEntity> {
    private static final Long DEFAULT_CATEGORY_PARENT_ID = 0L;

    /**
     * 添加类目
     */
    public ResponseDTO<String> add(CategoryAddForm addForm) {
        // 校验类目
        CategoryBaseEntity categoryEntity = SmartBeanUtil.copy(addForm, CategoryBaseEntity.class);
        ResponseDTO<String> res = this.checkCategory(categoryEntity, false);
        if (!res.getOk()) {
            return res;
        }
        // 没有父类则使用默认父类
        Long parentId = null == addForm.getParentId() ? NumberUtils.LONG_ZERO : addForm.getParentId();
        categoryEntity.setParentId(parentId);
        categoryEntity.setSort(null == addForm.getSort() ? 0 : addForm.getSort());
        categoryEntity.setDeletedFlag(0);

        // 保存数据
        this.getEntityMapper().insert(categoryEntity);

        // 更新缓存
        this.removeCache();
        return ResponseDTO.ok();
    }

    /**
     * 更新类目
     * 不能更新父级类目
     */
    public ResponseDTO<String> update(CategoryUpdateForm updateForm) {
        // 校验类目
        Long categoryId = updateForm.getCategoryId();
        CategoryBaseEntity optional = this.queryCategory(categoryId);
        CategoryBaseEntity categoryEntity = SmartBeanUtil.copy(updateForm, CategoryBaseEntity.class);

        /*
          不更新类目类型
          不更新父类id
         */
        Integer categoryType = optional.getCategoryType();
        categoryEntity.setCategoryType(categoryType);
        categoryEntity.setParentId(optional.getParentId());

        ResponseDTO<String> responseDTO = this.checkCategory(categoryEntity, true);
        if (!responseDTO.getOk()) {
            return responseDTO;
        }
        this.getEntityMapper().updateById(categoryEntity);

        // 更新缓存
        this.removeCache();
        return ResponseDTO.ok();
    }

    /**
     * 新增/更新 类目时的 校验
     */
    private ResponseDTO<String> checkCategory(CategoryBaseEntity categoryEntity, boolean isUpdate) {
        // 校验父级是否存在
        Long parentId = categoryEntity.getParentId();
        Integer categoryType = categoryEntity.getCategoryType();
        if (null != parentId) {
            if (Objects.equals(categoryEntity.getCategoryId(), parentId)) {
                return ResponseDTO.userErrorParam("父级类目怎么和自己相同了");
            }
            if (!Objects.equals(parentId, NumberUtils.LONG_ZERO)) {
                CategoryBaseEntity category = this.queryCategory(parentId);
                if (!Objects.equals(categoryType, category.getCategoryType())) {
                    return ResponseDTO.userErrorParam("与父级类目类型不一致");
                }
            }

        } else {
            // 如果没有父类 使用默认父类
            parentId = NumberUtils.LONG_ZERO;
        }

        // 校验同父类下 名称是否重复
        CategoryBaseEntity queryEntity = new CategoryBaseEntity();
        queryEntity.setParentId(parentId);
        queryEntity.setCategoryType(categoryType);
        queryEntity.setCategoryName(categoryEntity.getCategoryName());
        queryEntity.setDeletedFlag(0);
        queryEntity = this.getEntityMapper().selectOne(queryEntity);
        if (null != queryEntity) {
            if (isUpdate) {
                if (!Objects.equals(queryEntity.getCategoryId(), categoryEntity.getCategoryId())) {
                    return ResponseDTO.userErrorParam("同级下已存在相同类目~");
                }
            } else {
                return ResponseDTO.userErrorParam("同级下已存在相同类目~");
            }
        }
        return ResponseDTO.ok();
    }

    /**
     * 查询 类目详情
     */
    public ResponseDTO<CategoryVO> queryDetail(Long categoryId) {
        CategoryBaseEntity optional = this.queryCategory(categoryId);
        CategoryVO adminVO = SmartBeanUtil.copy(optional, CategoryVO.class);
        return ResponseDTO.ok(adminVO);
    }

    /**
     * 根据父级id 查询所有子类 返回层级树
     * 如果父类id 为空 返回所有类目层级
     */
    public ResponseDTO<List<CategoryTreeVO>> queryTree(CategoryTreeQueryForm queryForm) {
        if (null == queryForm.getParentId()) {
            if (null == queryForm.getCategoryType()) {
                return ResponseDTO.userErrorParam("类目类型不能为空");
            }
            queryForm.setParentId(NumberUtils.LONG_ZERO);
        }
        List<CategoryTreeVO> treeList = this.queryCategoryTree(queryForm.getParentId(), queryForm.getCategoryType());
        return ResponseDTO.ok(treeList);
    }

    /**
     * 删除类目
     * 如果有未删除的子类 则无法删除
     */
    public ResponseDTO<String> delete(Long categoryId) {
        CategoryBaseEntity optional = this.queryCategory(categoryId);

        List<Long> categorySubId = this.queryCategorySubId(Lists.newArrayList(categoryId));
        if (CollectionUtils.isNotEmpty(categorySubId)) {
            return ResponseDTO.userErrorParam("请先删除子级类目");
        }

        // 更新数据
        CategoryBaseEntity categoryEntity = new CategoryBaseEntity();
        categoryEntity.setCategoryId(categoryId);
        categoryEntity.setDeletedFlag(1);
        this.getEntityMapper().updateById(categoryEntity);

        // 更新缓存
        this.removeCache();
        return ResponseDTO.ok();
    }

    /**
     * 根据类目id 移除缓存
     */
    @CacheEvict(value = {AdminCacheConst.Category.CATEGORY_ENTITY, AdminCacheConst.Category.CATEGORY_SUB, AdminCacheConst.Category.CATEGORY_TREE}, allEntries = true)
    public void removeCache() {
        log.info("clear CATEGORY ,CATEGORY_SUB ,CATEGORY_TREE");
    }

    /**
     * 根据 id 查询未删除的类目
     *
     * @param categoryId
     * @return 可能 null
     */
    public CategoryBaseEntity queryCategory(Long categoryId) {
        if (null == categoryId) {
            return null;
        }
        CategoryBaseEntity entity = this.getById(categoryId);
        if (null == entity || entity.getDeletedFlag() == 1) {
            return null;
        }
        return entity;
    }


    /**
     * 查询类目 子级
     */
    @Cacheable(AdminCacheConst.Category.CATEGORY_SUB)
    public List<CategoryBaseEntity> querySubCategory(Long categoryId) {
        return this.getEntityMapper().queryByParentId(Lists.newArrayList(categoryId), 0);
    }

    /**
     * 查询类目 层级树
     * 优先查询缓存
     */
    @Cacheable(AdminCacheConst.Category.CATEGORY_TREE)
    public List<CategoryTreeVO> queryCategoryTree(Long parentId, Integer categoryType) {
        List<CategoryBaseEntity> allCategoryEntityList = this.getEntityMapper().queryByType(categoryType, 0);

        List<CategoryBaseEntity> categoryEntityList = allCategoryEntityList.stream().filter(e -> e.getParentId().equals(parentId)).collect(Collectors.toList());
        List<CategoryTreeVO> treeList = SmartBeanUtil.copyList(categoryEntityList, CategoryTreeVO.class);
        treeList.forEach(e -> {
            e.setLabel(e.getCategoryName());
            e.setValue(e.getCategoryId());
            e.setCategoryFullName(e.getCategoryName());
        });
        // 递归设置子类
        this.queryAndSetSubCategory(treeList, allCategoryEntityList);
        return treeList;
    }

    /**
     * 递归查询设置类目子类
     * 从缓存查询子类
     */
    private void queryAndSetSubCategory(List<CategoryTreeVO> treeList, List<CategoryBaseEntity> allCategoryEntityList) {
        if (CollectionUtils.isEmpty(treeList)) {
            return;
        }
        List<Long> parentIdList = treeList.stream().map(CategoryTreeVO::getValue).collect(Collectors.toList());
        List<CategoryBaseEntity> categoryEntityList = allCategoryEntityList.stream().filter(e -> parentIdList.contains(e.getParentId())).collect(Collectors.toList());
        Map<Long, List<CategoryBaseEntity>> categorySubMap = categoryEntityList.stream().collect(Collectors.groupingBy(CategoryBaseEntity::getParentId));
        treeList.forEach(e -> {
            List<CategoryBaseEntity> childrenEntityList = categorySubMap.getOrDefault(e.getValue(), Lists.newArrayList());
            List<CategoryTreeVO> childrenVOList = SmartBeanUtil.copyList(childrenEntityList, CategoryTreeVO.class);
            childrenVOList.forEach(item -> {
                item.setLabel(item.getCategoryName());
                item.setValue(item.getCategoryId());
                item.setCategoryFullName(e.getCategoryFullName() + StringConst.SEPARATOR_SLASH + item.getCategoryName());
            });
            // 递归查询
            this.queryAndSetSubCategory(childrenVOList, allCategoryEntityList);
            e.setChildren(childrenVOList);
        });
    }


    /**
     * 根据 类目id集合 查询未删除的类目集合
     */
    public Map<Long, CategoryBaseEntity> queryCategoryList(List<Long> categoryIdList) {
        if (CollectionUtils.isEmpty(categoryIdList)) {
            return Collections.emptyMap();
        }
        categoryIdList = categoryIdList.stream().distinct().collect(Collectors.toList());
        Map<Long, CategoryBaseEntity> categoryEntityMap = Maps.newHashMap();
        for (Long categoryId : categoryIdList) {
            CategoryBaseEntity categoryEntity = this.queryCategory(categoryId);
            if (categoryEntity != null) {
                categoryEntityMap.put(categoryId, categoryEntity);
            }
        }
        return categoryEntityMap;
    }


    /**
     * 根据类目id 递归查询该id的所有子类id 递归查询
     * 同时存入缓存
     * 注意：查询出来的集合 不包含传递的父类参数
     */
    public List<Long> queryCategorySubId(List<Long> categoryIdList) {
        if (CollectionUtils.isEmpty(categoryIdList)) {
            return Collections.emptyList();
        }
        //所有子类
        List<CategoryBaseEntity> categoryEntityList = Lists.newArrayList();
        categoryIdList.forEach(e -> {
            categoryEntityList.addAll(this.querySubCategory(e));
        });
        Map<Long, List<CategoryBaseEntity>> subTypeMap = categoryEntityList.stream().collect(Collectors.groupingBy(CategoryBaseEntity::getCategoryId));
        // 递归查询子类
        categoryIdList = subTypeMap.values().stream().flatMap(Collection::stream).map(CategoryBaseEntity::getCategoryId).distinct().collect(Collectors.toList());
        if (CollectionUtils.isEmpty(categoryIdList)) {
            return Lists.newArrayList();
        }
        categoryIdList.addAll(this.queryCategorySubId(categoryIdList));
        return categoryIdList;
    }


    /**
     * 处理类目名称
     */
    public List<String> queryCategoryName(List<Long> categoryIdList) {
        if (CollectionUtils.isEmpty(categoryIdList)) {
            return null;
        }
        Map<Long, CategoryBaseEntity> categoryMap = this.queryCategoryList(categoryIdList);
        List<String> categoryNameList = Lists.newArrayList();
        categoryIdList.forEach(e -> {
            CategoryBaseEntity categoryEntity = categoryMap.get(e);
            if (categoryEntity != null) {
                categoryNameList.add(categoryMap.get(e).getCategoryName());
            }
        });
        return categoryNameList;
    }

    /**
     * 根据类目id 查询类目名称
     */
    public String queryCategoryName(Long categoryId) {
        CategoryBaseEntity categoryEntity = this.queryCategory(categoryId);
        if (null == categoryEntity || categoryEntity.getDeletedFlag() == 1) {
            return null;
        }
        return categoryEntity.getCategoryName();
    }

    /**
     * 根据类目id 查询类目详情 包含类目全称 如：医考/医师资格/临床执业
     */
    public CategorySimpleDTO queryCategoryInfo(Long categoryId) {
        CategoryBaseEntity categoryEntity = this.queryCategory(categoryId);
        if (null == categoryEntity || categoryEntity.getDeletedFlag() == 1) {
            return null;
        }
        String fullName = this.queryFullName(categoryId);
        // 返回DTO
        CategorySimpleDTO categoryDTO = new CategorySimpleDTO();
        categoryDTO.setCategoryId(categoryId);
        categoryDTO.setCategoryName(categoryEntity.getCategoryName());
        categoryDTO.setCategoryFullName(fullName);
        categoryDTO.setParentId(categoryEntity.getParentId());
        return categoryDTO;
    }

    /**
     * 递归查询分类和所有父级类目
     * ps:特别注意返回的集合中 包含自己
     */
    public List<CategoryBaseEntity> queryCategoryAndParent(Long categoryId) {
        List<CategoryBaseEntity> parentCategoryList = Lists.newArrayList();
        CategoryBaseEntity categoryEntity = this.queryCategory(categoryId);
        if (null == categoryEntity || categoryEntity.getDeletedFlag() == 1) {
            return parentCategoryList;
        }

        // 父级始终放在第一位
        parentCategoryList.add(0, categoryEntity);
        Long parentId = categoryEntity.getParentId();
        if (Objects.equals(DEFAULT_CATEGORY_PARENT_ID, parentId)) {
            return parentCategoryList;
        }
        parentCategoryList.addAll(0, this.queryCategoryAndParent(parentId));
        return parentCategoryList;
    }

    /**
     * 查询 分类全称 如：医考/医师资格/临床执业
     */
    public String queryFullName(Long categoryId) {
        List<CategoryBaseEntity> parentCategoryList = this.queryCategoryAndParent(categoryId);
        // 拼接父级类目名称 斜杠分隔返回
        List<String> nameList = parentCategoryList.stream().map(CategoryBaseEntity::getCategoryName).collect(Collectors.toList());
        return StrUtil.join(StringConst.SEPARATOR_SLASH, nameList);
    }

    /**
     * 查询 分类全称 如：医考/医师资格/临床执业
     */
    public Map<Long, String> queryFullName(List<Long> categoryIdList) {
        if (CollectionUtils.isEmpty(categoryIdList)) {
            return Maps.newHashMap();
        }
        // 循环内查询的缓存 还ok
        return categoryIdList.stream().collect(Collectors.toMap(Function.identity(), this::queryFullName));
    }
}
